/*寻宝
题目描述
亮亮解出了卷轴隐藏的秘密，来到了一片沼泽地。这里有很多空地，而面试直通卡可能埋在任意一块空地中，好在亮亮发现了一堆木材，他可以将木材铺在两个空地之间的沼泽地上。因为亮亮不知道面试直通卡具体在哪一块空地中，所以必须要保证任意一块空地对于亮亮来说是可以抵达的。 “怎么还有鳄鱼！没办法，看来有些空地不能直接到达了。” 亮亮虽然没有洁癖，但是沼泽地实在太臭了，所以亮亮不会循环利用木材。而且木材不能拼接在一起使用，所以亮亮必须要知道在耗费木材最少的情况下，最长的那根木材至少需要多长。
输入描述:
第一行包含两个整数N(1≤N≤10000),M(1≤M≤1000000)。N表示公有N块空地。
接下来M行，每行包含两个整数P(1≤P≤N),Q(1≤Q≤N),K代表P,Q两个间没有鳄鱼，需要耗费K的木材。
输出描述:
一个整数，即耗费木材最少的情况下，最长的那根木材长度。
输入例子:
4 3
1 2 1
2 3 1
3 4 2
输出例子:
2
*/
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
const int maxn = 1000000 + 100;
using namespace std;

struct data
{
    int x;
    int y;
    int cost;
} a[maxn];
int par[maxn], n, m, maxx;

void Init()
{
    for (int i = 0; i < maxn; i ++)
        par[i] = i;
}

bool comp(const data &a, const data &b)
{
    return a.cost < b.cost;
}

int find(int x)
{
    if (x == par[x])
        return x;
    return  par[x] = find(par[x]);
}

void unite(int x, int y)
{
    x = find(x);
    y = find(y);
    if (x != y)
        par[x] = y;
}

bool same(int x, int y)
{
    return find(x) == find(y);
}

void solve()
{
    sort(a, a + m, comp);
    int sum = 0;
    for (int i = 0; i < m; i ++)
    {
        if (!same(a[i].x, a[i].y))
        {
            unite(a[i].x, a[i].y);
            ++ sum;
        }
        // n 个点，所以最少需要 n-1 条边就可以连接起来
        if (sum == n - 1)
        {
            // 由于已经从小到大排好序了，所以这个就是最大值
            printf("%d\n", a[i].cost);
            return;
        }
    }
}

int main()
{
    while (~scanf("%d%d", &n, &m))
    {
        Init();
        for (int i = 0; i < m; i ++)
            scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].cost);
        solve();
    }
    return 0;
}
